package com.yanggeng.demo.beginnerguidedemo.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionUtils {

    /**
     * 利用类对象、方法名和参数列表 执行方法
     * @param object 方法执行的对象
     * @param methodName 类的一个方法名，该方法不包括父类方法，可能是私有方法
     * @param args 参数列表
     * @return 调用方法后的返回值
     * @throws Exception
     */
    public static Object invoke(Object object, String methodName, Object... args) throws Exception {

        Class clazz = object.getClass();
        Class[] paramsTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            paramsTypes[i] = args[i].getClass();
        }
        Method method = clazz.getDeclaredMethod(methodName, paramsTypes);
        method.setAccessible(true);
        return method.invoke(object, args);
    }

    /**
     * 使用全类名和方法名执行方法
     * @param className 类的全类名
     * @param methodName 执行的方法名，该方法不包括父类方法，可能是私有方法
     * @param args 参数列表
     * @return 执行方法后的结果
     */
    public static Object invoke(String className, String methodName, Object... args) {

        Object object = null;

        try {
            object = Class.forName(className).newInstance();
            return invoke(object, methodName, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object invoke2(Object object, String methodName, Object...args) {
        Class[] paramsTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            paramsTypes[i] = args[i].getClass();
        }

        try {
            Method method = getMethod(object.getClass(), methodName, paramsTypes);
            method.setAccessible(true);
            return method.invoke(object, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Method getMethod(Class clazz, String methodName, Class...paramsTypes) {
        for (;clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                return clazz.getDeclaredMethod(methodName, paramsTypes);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
